package com.hmc.test;

import java.io.Serializable;
import java.util.AbstractMap;
import java.util.Map;
import java.util.Set;

public class MyHashMap<P, V> extends AbstractMap<P, V>{
    //这个是最大的一个2次幂值
    private final int MAXMUM_CAPACITY = 1 << 30;
    //为什么是0.75，因为大于0.75会是hash碰撞几率增大，太小的话，空间浪费太严重
    private final float DEFAULT_LOAD_FACTORY = 0.75F;
    //负载因子，表示这个集合的最大负载率
    private float loadFactory;
    //容量
    private int capacity;
    //阈(yu)值，hash桶的可用最大容量，等于loadFactory*capacity
    private int threshold;
    //表示hash桶中存放的元素个数
    private int size;

    //无参构造方法，初始化负载因子
    public MyHashMap() {
        this.loadFactory = DEFAULT_LOAD_FACTORY;
    }

    @Override
    public Set<Entry<P, V>> entrySet() {
        return null;
    }

    /**
     * 自定义初始容量和负载因子
     *
     * @param loadFactory     负载因子
     * @param initialCapacity 初始容量，这个并不是集合使用的容量，需要进行处理，变为不小于这个值的最小的2次幂值
     */
    public MyHashMap(float loadFactory, int initialCapacity) throws Exception {
        //判断值是否合法
        if (loadFactory <= 0 || Float.isNaN(loadFactory))
            throw new IllegalArgumentException("illegal loadFactory exception:loadFactory=" + loadFactory);
        if (initialCapacity <= 0)
            throw new IllegalArgumentException("illegal initialCapacity exception:initialCapacity=" + initialCapacity);
        //判断容量是否大于最大容量，如果大于最大容量，那么就使用最大容量作为真实值
        if (initialCapacity > MAXMUM_CAPACITY)
            initialCapacity = MAXMUM_CAPACITY;
        //将值传给全局变量
        this.loadFactory = loadFactory;
        //不使用传入的值作为容量，而是用不小于这个值的最小2次幂作为容量
        /**
         * 当容量为2的幂值时，取余可以用二进制表示 求x%n == (n-1)&x
         */
        this.capacity = tableSizeOf(initialCapacity);
    }

    /**
     * 返回一个不小于n的最小2次幂
     * 有点：后面用于确定值的位置时，可以用二进制进行取余运算
     *
     * @param n
     * @return
     */
    private int tableSizeOf(int n) {
        n = n - 1;
        n |= n >>> 1;
        n |= n >>> 2;
        n |= n >>> 4;
        n |= n >>> 8;
        n |= n >>> 14;
        n = (n > MAXMUM_CAPACITY) ?
                MAXMUM_CAPACITY :
                ((n < 0) ? 1 : n + 1);
        return n;
    }

}
